package com.lmaye.eshop.inventory.service.impl;

import com.lmaye.eshop.inventory.request.Request;
import com.lmaye.eshop.inventory.request.RequestMemoryQueue;
import com.lmaye.eshop.inventory.service.RequestAsyncProcessService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.concurrent.ArrayBlockingQueue;

/**
 * <pre>
 *   ┏┓　　　┏┓
 * ┏┛┻━━━┛┻┓
 * ┃　　　　　　　┃
 * ┃　　　━　　　┃
 * ┃　┳┛　┗┳　┃
 * ┃　　　　　　　┃
 * ┃　　　┻　　　┃
 * ┃　　　　　　　┃
 * ┗━┓　　　┏━┛
 * 　　┃　　　┃神兽保佑
 * 　　┃　　　┃代码无BUG！
 * 　　┃　　　┗━━━┓
 * 　　┃　　　　　　　┣┓
 * 　　┃　　　　　　　┏┛
 * 　　┗┓┓┏━┳┓┏┛
 * 　　　┃┫┫　┃┫┫
 * 　　　┗┻┛　┗┻┛
 * </pre>
 * -- RequestAsyncProcessServiceImpl 请求异步处理Service实现类
 *
 * @author lmay.Zhou
 * @date 2019/3/19 23:53 星期二
 * @qq 379839355
 * @email lmay@lmaye.com
 */
@Slf4j
@Service
public class RequestAsyncProcessServiceImpl implements RequestAsyncProcessService {
    /**
     * 请求处理
     *
     * @param request   请求对象
     */
    @Override
    public void process(Request request) {
        try {
            // 请求的路由，根据每个请求的商品ID路由到对应的内存队列中去
            ArrayBlockingQueue<Request> queue = getRoutingQueue(request.getProductId());
            // 将请求放入对应的队列中，完成路由操作
            queue.put(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取路由到内存队列
     *
     * @param productId 商品ID
     * @return  ArrayBlockingQueue
     */
    private ArrayBlockingQueue<Request> getRoutingQueue(Integer productId) {
        RequestMemoryQueue requestMemoryQueue = RequestMemoryQueue.getInstance();
        // 先获取productId的hash值
        String key = String.valueOf(productId);
        int h;
        int hash = StringUtils.isBlank(key) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        /**
         * 对hash值取模，将hash值路由到指定的内存队列中，比如内存队列大小8
         * 用内存队列的数量对hash值取模之后，结果一定是在0~7之间
         * 所以任何一个商品ID都会被固定路由到同样的一个内存队列中去
         */
        int index = (requestMemoryQueue.queueSize() - 1) & hash;
        log.info("************** 演示: 路由到内存队列 - 商品id [{}], 队列索引 [{}]", productId, index);
        return requestMemoryQueue.getQueue(index);
    }
}
